package ar.edu.unicen.pladema.resources;

import java.io.File;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public final class ResourceManager {
	/** logger. */
	private static Log log = LogFactory.getLog(ResourceManager.class);
	
	private static final String CONFIG_FILE = "config.properties";
	private static final String TEXT_FILE = "text.properties";
	private static final String MTYPE_DESC_FILE = "mt-desc.properties";
	private static final String MTYPE_READER_FILE = "mt-readers.properties";
	private static final String CONFIG_PARAM_DIRECTORIES = "DirectoryToIndex";
	private static final String CONFIG_PARAM_INDEX = "IndexDirectory";
	
	private static ResourceManager instance = null;
	/**
	 * Almacena la configuración de la aplicación. No utilizar directamente.
	 * @see #getProperties() 
	 */
	private ConfigMap properties = null;
	private ConfigMap lang = null;
	private ConfigMap mTypeDesc = null;
	private ConfigMap mTypeReader = null;
	
	/**
	 * Implemento un singleton para manejar la configuración.
	 */
	private ResourceManager() {
		properties = new ConfigMap(getResoursesPath() + CONFIG_FILE, false);
		lang = new ConfigMap(getResoursesPath() + TEXT_FILE, false);
		mTypeDesc = new ConfigMap(getResoursesPath() + MTYPE_DESC_FILE, true);
		mTypeReader = new ConfigMap(getResoursesPath() 
				+ MTYPE_READER_FILE, true);
		
	}
	
	/**
	 * Método para obtener la instancia única de la clase.
	 * @return una instancia de {@link ResourceManager}
	 */
	public static ResourceManager getInstance() {
		if (instance == null) {
			instance = new ResourceManager();
		}
		return instance;
	}
	
	/**
	 * Método que retorna el valor de configuración de una clave dada.
	 * 
	 * @param key Clave de configuración.
	 * @return Valor de la clave.
	 */
	public String getConfig(final String key) {
		return properties.getProperty(key);
	}
	/**
	 * Método que retorna una lista de valores para una clave dada.
	 * Para la configuración específica de la aplicación existen
	 * métodos particulares: {@link #getDirectoriesToIndex()}.
	 *  
	 * @param key Clave de configuración
	 * @return Valores de la clave.
	 */
	public Vector<String> getConfigList(final String key) {
		return properties.getPropertyList(key);
	}
	
	/**
	 * Método que retorna un valor de configuración para una clave dada.
	 * Para la configuración específica de la aplicación existen métodos
	 * particulares: {@link #getIndexDirectory()}
	 * 
	 * @param key Clave de configuración
	 * @param value Valor de la clave.
	 */
	public void setConfig(final String key, final String value) {
		properties.setProperty(key, value);
	}
	public void setConfigList(final String key, final Vector<String> values) {
		properties.setPropertyList(key, values);
	}
	public void setConfigList(final String key, final String[] values) {
		 Vector<String> valuesVector = arrayToVector(values);
		setConfigList(key, valuesVector);
	}

	public void saveProperties() {
		try {
			properties.save("GUI config");
		} catch (Exception e) {
			log.error(e, e);
		}
	}
	/**
	 * Método utilitario para obtener la dirección del directorio de
	 * recursos.
	 * 
	 * @return dirección del directorio de recursos.
	 */
	protected String getResoursesPath() {
		return "";
	}
	
	/**
	 * Método utilitario para obtener la dirección del directorio de
	 * imágenes.
	 * 
	 * @return dirección del directorio de imágenes.
	 */
	protected String getImagesPath() {
		return getResoursesPath() + "img" + File.separator; 
	}
	
	/**
	 * Retorna la lista de directorios que serán indexados.
	 * 
	 * @return lista de directorios
	 */
	public Vector<String> getDirectoriesToIndex() {
		return getConfigList(CONFIG_PARAM_DIRECTORIES);
	}
	
	/**
	 * Setea la lista de directorios que serán indexados.
	 * 
	 * @param values lista de directorios
	 */
	public void setDirectoriesToIndexVector(final Vector<String> values) {
		setConfigList(CONFIG_PARAM_DIRECTORIES, values);
	}
	/**
	 * Setea la lista de directorios que serán indexados.
	 * 
	 * @param values lista de directorios
	 */
	public void setDirectoriesToIndexVector(final String[] values) {
		setConfigList(CONFIG_PARAM_DIRECTORIES, values);
	}
	
	/**
	 * Retorna el directorio donde está guardado el índice.
	 * 
	 * @return directorio del indice.
	 */
	public String getIndexDirectory() {
		String indexPath = getConfig(CONFIG_PARAM_INDEX);
		if (indexPath == null) {
			File f = new File("indice");
			return f.getAbsolutePath();
		}
		return indexPath;
	}
	/**
	 * Setea el directorio donde está guardado el índice.
	 * 
	 * @param value directorio del indice.
	 */
	public void setIndexDirectory(final String value) {
		setConfig(CONFIG_PARAM_INDEX, value);
	}
	

	
	/**
	 * Retorna el valor de la clave key.
	 * @param key clave del texto a buscar.
	 * @return Valor para la clave.
	 */
	public String getText(final String key) {
		String result = lang.getProperty(key);
		if (result == null) {
			result = "key:" + key;
			log.warn("Missing key, please add it: " + key);
			System.err.println("Missing key, please add it: " + key);
		}
		return result;
	}
	public String getMTDescription(final String mimeType) {
		String result = mTypeDesc.getProperty(mimeType);
		if (result == null) {
			log.debug("Missing key, please add it: " + mimeType);
			//System.err.println("Missing key, please add it: " + mimeType);
		}
		return result;
	}
	public ConfigMap getMTDescriptions() {
		return mTypeDesc;
	}
	public String getMTReaderCode(final String mimeType) {
		String result = mTypeReader.getProperty(mimeType);
		if (result == null) {
			log.debug("Missing key, please add it: " + mimeType);
			//System.err.println("Missing key, please add it: " + mimeType);
		}
		return result;
	}
	/**
	 * Retorna el valor de la clave key. Se utiliza un Array de reemplazos
	 * para completar el valor encontrado con los valores del Array.
	 * 
	 * @param key clave del texto a buscar.
	 * @param replacements Reemplazos a realizar.
	 * @return Valor para la clave.
	 */
	public String getText(final String key, final String[] replacements) {
		String result = getText(key);
		if (replacements == null) {
			return result;
		}
		if (replacements.length == 0) {
			return result;
		}
		
		int i = 0;
		while (i < replacements.length) {
			result = result.replaceFirst("_", replacements[i]);
			i = i + 1;
		}
		return result;
	}
	/**
	 * Convierte un Array de String a un Vector de String.
	 * @param items Array de String.
	 * @return Vector de String
	 */
	private Vector<String> arrayToVector(final String[] items) {
		Vector<String> directories = new Vector<String>();
		for (String directory : items) {
			directories.add(directory);
		}
		return directories;
	}

}
